﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using TByte.XnaHelper.GameObjects;

namespace TByte.XnaHelper.Particles
{
    /// <summary>
    /// Emitter of particles
    /// </summary>
    public class Emitter : GameObject
    {
        #region Fields
        Vector2 previousPosition = Vector2.Zero;
        float particlesPerLoop; //Amount of particles per loop
        float waitList = 0; //Amount of particles waiting to be spawned
        bool paused = true;
        float size;
        float ttl;
        List<ParticleModifier> modifiers = new List<ParticleModifier>();
        RenderTarget2D renderTarget;
        SpriteSheet sheet;
        SpriteBatch spriteBatch;
        List<Particle> particles = new List<Particle>();
        #endregion

        #region Methods
        /// <summary>
        /// Update Emitter. (Updates all particles sent out by the emitter)
        /// </summary>
        public override void Update()
        {
            //If the emitter isn't paused, it will call the Shoot method.
            if (!paused)
            {
                Shoot();
            }

            //Loop through all particles. Kill if the particle isn't alive, otherwise Update the particle.
            for (int i = particles.Count() - 1; i >= 0; i--)
            {
                //Update all particles that are alive.
                if (particles[i].isAlive)
                {
                    particles[i].Update();
                }
                else
                {
                    //Remove the dead particle
                    particles.RemoveAt(i);
                }
            }

            //Update previous position
            previousPosition = Position;
        }
        /// <summary>
        /// Draw all particles on the screen.
        /// </summary>
        /// <param name="s">Opened Spritebatch.</param>
        public override void Draw(SpriteBatch spriteBatch)
        {
            RenderTargetBinding[] targets = Manager.GraphicsDevice.GetRenderTargets();

            //Set render target
            Manager.GraphicsDevice.SetRenderTarget(renderTarget);
            Manager.GraphicsDevice.Clear(Color.Transparent);

            //Begin spriteBatch
            if (Manager.CurrentCamera == null)
            {
                this.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
            }
            else
            {
                this.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, null, null, null, Manager.CurrentCamera.TransformMatrix);
            }

            //Draw particles
            foreach (Particle p in particles)
            {
                p.Draw(this.spriteBatch);
            }

            //End spriteBatch
            this.spriteBatch.End();

            //Reset render target
            if (targets.Count() > 0)
            {
                Manager.GraphicsDevice.SetRenderTarget((RenderTarget2D)targets[0].RenderTarget);
            }
            else
            {
                Manager.GraphicsDevice.SetRenderTarget(null);
            }
            Manager.GraphicsDevice.Clear(Color.Transparent);

            //Draw render
            if (Manager.CurrentCamera == null)
            {
                spriteBatch.Draw((Texture2D)renderTarget, Vector2.Zero, Color.White);
            }
            else
            {
                spriteBatch.Draw((Texture2D)renderTarget, Manager.CurrentCamera.CameraPosition, Manager.ScreenRectangle, Color.White, -Manager.CurrentCamera.Rotation, Manager.Screen / 2, 1 / Manager.CurrentCamera.Zoom, SpriteEffects.None, 0);
            }
        }
        /// <summary>
        /// Start spawning particles every Update.
        /// </summary>
        public void Start()
        {
            paused = false;
        }
        /// <summary>
        /// Pause spawning particles.
        /// </summary>
        public void Pause()
        {
            paused = true;
        }
        /// <summary>
        /// Spawn a single batch of particles. (if paused == false then Shoot is called every Update)
        /// </summary>
        public void Shoot()
        {
            waitList += particlesPerLoop; //Add new particles to waitlist

            //Spawn particles and empty waitlist
            int spawnQue = (int)waitList;
            waitList -= spawnQue;
            for (int i = 0; i < spawnQue; i++)
            {
                //Spawn a particle
                if (Position != previousPosition)
                {

                }
                Particle newParticle = new Particle(ttl, new Vector2(MathHelper.Lerp(previousPosition.X, Position.X, ((float)i + 1f) / spawnQue), MathHelper.Lerp(previousPosition.Y, Position.Y, ((float)i + 1f) / spawnQue)), size, color, sheet,Manager.Random.Next(sheet.Count), modifiers, this);

                //Add particle to list
                particles.Add(newParticle);
            }
        }
        public void Move(Vector2 direction)
        {
            RelativePosition += direction;
        }
        public void MoveTo(Vector2 position)
        {
            RelativePosition = position;
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Emitter of particles
        /// </summary>
        /// <param name="beginSize">Size of particle on spawn</param>
        /// <param name="endSize">Size of particle on dreath (lerp)</param>
        /// <param name="beginColor">Color of particle on spawn</param>
        /// <param name="endColor">Color of particle on death (fade)</param>
        /// <param name="particlesPerLoop">Amount of particles spawned per loop. (Every time Shoot() is called)</param>
        /// <param name="spawnSpeed">Maximum speed of the particle on spawn. (MAXIMUM)</param>
        public Emitter(float particlesPerLoop, float ttl, SpriteSheet sheet, List<ParticleModifier> mods)
            :base("Emitter")
        {
            this.color = Color.White;
            this.size = 1;
            this.particlesPerLoop = particlesPerLoop;
            this.sheet = sheet;
            this.ttl = ttl;
            this.modifiers = mods;

            this.renderTarget = new RenderTarget2D(Manager.GraphicsDevice, Manager.GraphicsDevice.Viewport.Width, Manager.GraphicsDevice.Viewport.Height, true, Manager.GraphicsDevice.DisplayMode.Format,DepthFormat.Depth24);
            this.spriteBatch = new SpriteBatch(Manager.GraphicsDevice);
        }
        #endregion

        #region Properties
        public List<ParticleModifier> Modifiers { get { return modifiers; } set { modifiers = value; } }
        #endregion
    }
}
